<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Book extends Model
{
    use HasFactory;

    /*

     * 这里简单说明一下__call方法的作用。

      在PHP中，当我们访问一个不存在的类方法时，就会调用这个类的__call()方法。

      （如果类方法不存在，又没有写__call()方法，PHP会直接报错）

       当调用存在的getById(50)方法时，程序打印：我的ID是50。

       而如果调用不存在的getAge()方法时，程序就会执行到A类的__call()方法里面，这里会打印：类Book不存在方法getAge。

这就是__call的原理。


        我们希望调用方法:
        (new Book)->getById(100);           // 原始的、不用缓存的调用方式，还是原来的方式，一般是读取数据库的数据。
        (new Book)->getByIdCache(100);      // 使用缓存的调用方式，缓存键名为：app_models_book:getbyid: + md5(参数列表)
        (new Book)->getByIdClear(100);      // 删除这个缓存
        (new Book)->getByIdFlush();         // 删除 getById() 方法对应的所有缓存，即删除 app_models_book:getbyid:*。这个方法不需要参数。

        从上面的例子，我们看到，__call()方法被调用时，会传入两个参数。
        name：想要调用的方法名arguments：参数列表
        我们就可以在参数上面做文章。




     */

    public function __call($name, $arguments)
    {
        echo '类Book不存在该方法:', $name, PHP_EOL;

        if (strlen($name) < 5){
            exit('Method does not exist');
        }

        $method = substr($name, 0,-5);
        $action = substr($name, -5);

        //当前的类名称
        $class = get_class();

        //生成缓存键名
        $key = sprintf('%s:%s',str_replace('\\','_',$class),$method);
        // 都用小写好看点
        $key = strtolower($key);

        switch ($action){
            case 'Cache':
                // 缓存键名加上$arguments
                $key = $key . md5(json_encode($arguments));
                $data = Common::redis()->get($key);
                // 如果Redis中有数据
                if ($data !== false) {
                    $decodeData = json_decode($data, JSON_UNESCAPED_UNICODE);
                    // 如果不是JSON格式的数据，直接返回，否则返回json解析后的数据
                    return $decodeData === null ? $data : $decodeData;
                }
                // 如果Redis中没有数据则继续往下执行

                // 如果原方法不存在
                if (method_exists($this, $method) === false) {
                    exit('Method does not exist.');
                }
                // 调用原方法获取数据
                $data = call_user_func_array([$this, $method], $arguments);

                // 保存数据到Redis中以便下次使用
                Common::redis()->set($key, json_encode($data), 3600);

                // 结束执行并返回数据
                return $data;

                break;
            case 'Clear':

                // 缓存键名加上$arguments
                $key = $key . md5(json_encode($arguments));
                return Common::redis()->del($key);

                break;
            case 'Flush':

                $key = $key . '*';

                // 获取所有符合 $class:$method:* 规则的缓存键名
                $keys = Common::redis()->keys($key);
                return Common::redis()->del($keys);
                break;
            default:
                exit('Method does not exist.');

        }




    }

    public function getById($id)
    {
        echo '我的ID是', $id, PHP_EOL;
    }


}
